
可以发现:对于\(x\),可以直接转移到\(x\)的点只有,\(x-2^0\),\(x-2^1\),\(x-2^2\),…,\(x-2^k\) (\(k\)满足\(2^k < lowbit(x)\)且\(2^{k+1}>=lowbit(x)\))
若\(x = 1010000\)
\[ \begin{matrix} &=& 1001000 &+& lowbit(1001000) &=& 1001000 &+& 1000 &=& 1001000 &+& 2^3 \\ &=& 1001100 &+& lowbit(1001100) &=& 1001100 &+& 100 &=& 1001100 &+& 2^2 \\ &=& 1001110 &+& lowbit(1001110) &=& 1001110 &+& 10 &=& 1001110 &+& 2^1 \\ &=& 1001111 &+& lowbit(1001111) &=& 1001111 &+& 1 &=& 1001111 &+& 2^0\\ \end{matrix} \]
利用上面的性质,在树状数组的尾部插入数据,来建立一个树状数组
1
2
3
4
5
6
7void push(int pos){ int i,lb = lowbit(pos); c[pos] = a[pos]; for(i=1;i<lb;i <<=1){ c[pos] = max(c[pos],c[pos-i]); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20/* pos 位置,v 数值 */ void update(int pos,int v){ int i,lb; c[pos] = a[pos] = v; lb = lowbit(pos); for(i=1;i<lb;i <<=1){ //利用孩子更新自己 c[pos] = c[pos] > c[pos-i] ? c[pos] : c[pos-i]; } int pre = c[pos]; pos+=lowbit(pos);//父亲的位置 /* 更新父亲 */ while(pos <= n){ if( c[pos] < pre){ //更新的父亲 c[pos] = pre; pos +=lowbit(pos); } //没有更新父亲 else break; } }
设\(query(x,y)\)求区间\([x,y]\)之间的最值, 已知\(c[x]\)表示\([x-lowbit(x)+1,x]\)之间的最值,那如何求区间\([x,y]\)的最值呢?
graph g {
node[shape=rect width=1 style=filled fillcolor="lightblue"];
1[pos="1,0!"];
2[pos="2,0!"];
3[pos="3,0!"];
4[pos="4,0!"];
5[pos="5,0!"];
6[pos="6,0!"];
7[pos="7,0!"];
8[pos="8,0!"];
node[shape=circle width=0.5 style=filled fillcolor="white"];
c1[pos="1,0.55!" label="1"];
c2[pos="2,1.55!" label="2"];
c3[pos="3,0.55!" label="3"];
c4[pos="4,2.55!" label="4"];
c5[pos="5,0.55!" label="5"];
c6[pos="6,1.55!" label="6"];
c7[pos="7,0.55!" label="7"];
c8[pos="8,3.55!" label="8"];
c8--c4--c2--c1;
c2--2;
c4--{c3,4};
c6--{c5,6};
c8--{c6,c7,8};
}
想一想:
所以,我们发现下面的规律, 因为\(y-lowbit(y)+1\)表示\(c[y]\)结点所管辖范围的最左边的点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//求区间[x,y]的最大值 int query(int x,int y){ int res = -1; while(x <= y){ int nx = y - lowbit(y)+1; //最左边的点 if(nx >= x ){ res = res < c[y] ? c[y] :res; y = nx-1; // 下一个求解区间 } else { // nx < x res = res < a[y] ? a[y] :res; y--; } } return res; }
特点:
综上:
树状数组求区间最值特别适合那些:一边在尾部添加数据,一边查询最值的题目
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35struct Bit_max { T a[maxn],c[maxn]; // a是原数组 comp com; inline int lowbit(T x) { return x & -x; } inline int fa(int p) { return p+lowbit(p); } inline int left(int p) { return p-lowbit(p); } inline T g(T a ,T b) { return com(a,b) ? a : b;} void update_by_child(int p,T v){ //alias push c[p] = a[p] = v; int lb = lowbit(p); for(int i=1;i < lb ;i <<= 1) c[p] = g(c[p],c[p-i]); } void update(int p,T v){ update_by_child(p, v); T t = c[p]; for( p = fa(p); p<=N ; p = fa(p)){ if( com(t,c[p]) ) c[p] = t; else break; } } T query(int l,int r){ // 求区间最值 T ret = a[l]; for( ; l <=r; ){ int next = left(r)+1; if( next >= l ) ret = g(ret,c[r]) , r = next-1; else ret = g(ret,a[r]) , r--; } return ret; } }; Bit_max<ll> bit;
| 题目 | 地址 |
|---|---|
| 「2019冬令营提高组」 全连 | war3oj 10099 |